﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using Services.BusinessObjects.Log;
using Types.CustomTypes;
using Types.Enumerations;

namespace Services.Tools
{
    internal class ErrorHandlerBehavior : BusinessBase, IServiceBehavior, IErrorHandler
    {
        #region IServiceBehavior Members

        public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            return;
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher chDispatcher in serviceHostBase.ChannelDispatchers)
            {
                chDispatcher.ErrorHandlers.Add(this);
            }
        }

        public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            return;
        }

        #endregion

        #region IErrorHandler Members

        public bool HandleError(Exception error)
        {
            //Works in same thread

            //If you need to handle errors in this event, necessary codes should be written here

            return true; // handled.
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            FaultException<CCustomException> fe = ConvertExceptionType(error);
            MessageFault mFault = fe.CreateMessageFault();
            fault = Message.CreateMessage(version, mFault, fe.Action);
        }

        public FaultException<CCustomException> ConvertExceptionType(Exception error)
        {
            //NOTE: All errors occured in service thrown as FaultException 
            CCustomException oError;

            if (error is ApplicationException)
            {
                oError = new CCustomException(EnumExceptionType.ApplicationException, "Uygulama Hatası", "WcfServer");
                if (error.InnerException != null) oError.InnerExceptionString = error.InnerException.Message; else oError.InnerExceptionString = error.Message;
            }
            else
            {
                string failedQuery = string.Empty;
                string method = string.Empty;
                string excptn = string.Empty;
                string message = error.Message;
                string logKey = string.Empty;

                ExceptionLogBS hlBs = new ExceptionLogBS();
                if (!hlBs.IsExceptionInUnlogList(message))
                {
                    failedQuery = error.Data["SQL"] == null ? string.Empty : error.Data["SQL"].ToString();
                    method = error.Data["Method"] == null ? error.TargetSite.ToString() : error.Data["Method"].ToString();
                    excptn = error.ToString();

                    if (failedQuery != string.Empty)
                    {
                        failedQuery = "INCORRECT SQL CLAUSE: \r\n " + failedQuery;
                        if (excptn.Length > 0) excptn += "\r\n" + failedQuery; else excptn = failedQuery;
                    }

                    logKey = hlBs.LogException(excptn, message, "WcfServer", method);
                }

                //If error won't be logged then logKey value returns empty
                if (logKey == string.Empty)
                    oError = new CCustomException(EnumExceptionType.CanceledException, "Error to be Unlogged", "WcfServer");
                else
                    oError = new CCustomException(EnumExceptionType.SystemException, excptn, error.Message, "WcfServer", method, logKey);
            }

            if (error.Data["SQL"] != null) error.Data.Remove("SQL");
            if (error.Data["Method"] != null) error.Data.Remove("Method");

            FaultException<CCustomException> fe = new FaultException<CCustomException>(oError, new FaultReason(oError.ErrorMessage), new FaultCode(oError.ErrorCode));
            return fe;
        }

        #endregion
    }

    public class ErrorHandlerBehaviorExtension : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(ErrorHandlerBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new ErrorHandlerBehavior();
        }
    }

}
